
#include "netser.hpp"
#include <arpa/inet.h>
#include <cstring>
#include <iostream>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>

netser::netser(int port)
{
    int ret = 0;
    struct sockaddr_in address;
    int addrlen = sizeof(address);

    ser_port = port;

    ser_fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (ser_fd < 0) {
        std::cerr << "Could not create socket" << std::endl;
    }

    memset(&address, 0, sizeof(address));
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(ser_port);
    ret = bind(ser_fd, (struct sockaddr*)&address, sizeof(address));
    if (ret < 0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }
}

netser::~netser()
{
    close(ser_fd);
}

int netser::send(char* buf, size_t len, struct sockaddr_in* addr)
{
    int ret = 0;

    ret = sendto(ser_fd, (const char*)buf, len, MSG_CONFIRM, (struct sockaddr*)addr, sizeof(struct sockaddr_in));
    if (ret < 0) {
        std::cerr << "Send failed, ret = " << ret << std::endl;
        return -1;
    }

    return 0;
}

int netser::recv(char* buf, size_t size, struct sockaddr_in* addr)
{
    int ret = 0;
    socklen_t len = 0;

    len = sizeof(struct sockaddr_in); // 这行很关键，没有这行对端的ip接收会出错
    ret = recvfrom(ser_fd, (char*)buf, size, MSG_WAITALL, (struct sockaddr*)addr, &len);
    if (ret < 0) {
        std::cerr << "Receive failed" << std::endl;
        return -1;
    }
    buf[ret] = '\0';

    return 0;
}

int netser::start()
{
    if (!handle.joinable()) {
        running = true;
        handle = std::thread(&netser::thread, this);
    }

    return 0;
}

int netser::stop()
{
    if (handle.joinable()) {
        running = false;
        handle.join();
    }

    return 0;
}

void netser::thread()
{
    int ret = 0;
    size_t size = 1024;
    char* buf = NULL;
    struct sockaddr_in cli_addr;
    unsigned addrlen = 0;

    buf = new char[1024];
    memset(&cli_addr, 0, sizeof(struct sockaddr_in));

    while (running) {
        ret = recv(buf, size, &cli_addr);
        if (ret < 0) {
            std::cerr << "err: recv()" << std::endl;
        }

        std::cout << inet_ntoa(cli_addr.sin_addr) << "/" << cli_addr.sin_port << ": " << buf << std::endl;

        std::string command(buf);
        if (command == "connect") {
            if (!thd.joinable()) {
                run = true;
                thd = std::thread([this, &cli_addr]() {
                    this->publish(cli_addr);
                });
            }
        } else if (command == "disconnect") {
            if (thd.joinable()) {
                run = false;
                thd.join();
            }
        } else {
            std::cout << "Command is neither connect nor disconnect." << std::endl;
        }
    }

    delete[] buf;
}

// void netser::publish(struct sockaddr_in* addr)
void netser::publish(sockaddr_in& addr)
{
    char buf[32] = "hello aiit";

    while (run) {
        send(buf, strlen(buf), &addr);
        usleep(40 * 1000);
    }
}
